home *** CD-ROM | disk | FTP | other *** search
-
- VECTORS SEGMENT AT 0H
- ORG 9H*4
- KEYBOARD_INT_VECTOR LABEL DWORD
- ORG 16H*4
- KEYBOARD_IO_VECTOR LABEL DWORD
- VECTORS ENDS
-
- ROM_BIOS_DATA SEGMENT AT 40H
- ORG 17H
- KBD_FLAG DB ?
- ORG 1AH
- ROM_BUFFER_HEAD DW ?
- ROM_BUFFER_TAIL DW ?
- KB_BUFFER DW 16D DUP (?)
- KB_BUFFER_END LABEL WORD
- ROM_BIOS_DATA ENDS
- CODE_SEG SEGMENT
- ASSUME CS:CODE_SEG
- ORG 100H
- BEGIN: JMP INIT_VECTORS ;Initialize vectors and attach to DOS
- ROM_KEYBOARD_INT DD
- ROM_KEYBOARD_IO DD
- BUFFER_HEAD DW OFFSET KEYBOARD_BUFFER
- BUFFER_TAIL DW OFFSET KEYBOARD_BUFFER
- KEYBOARD_BUFFER DW 160D DUP(0) ;159 character input buffer
- KEYBOARD_BUFFER_END LABEL WORD
-
- ;--------------------------------------------------------;
- ; This procedure sends a short beep when the buffer fills
- ;--------------------------------------------------------;
-
- KB_CONTROL EQU 61H ;Control bits for keyboard & speaker
- ERROR_BEEP PROC NEAR
- PUSH AX
- PUSH BX
- PUSH CX
- PUSHF ;Save old interupt enable flag
- CLI ;Turn off beep during interupt
- MOV BX,30D ;Number of cycles for 1/8 second tone
- IN AL,KB_CONTROL ;Get information from speaker port
- PUSH AX ;Save control information
- START_OF_ONE_CYCLE:
- AND AL,0FCH ;Turn off speaker
- OUT KB_CONTROL,AL
- MOV CX,60D ;Delay for one half cycle
- OFF_LOOP:
- LOOP OFF_LOOP
- OR AL,2 ;Turn off speaker
- OUT KB_CONTROL,AL
- MOV CX,60D ;Delay for second half cycle
- ON_LOOP:
- LOOP ON_LOOP
- DEC BX ;200 cycles yet?
- JNZ START_OF_ONE_CYCLE
- POP AX ;Recover old keyboard information
- OUT KB_CONTROL,AL
- POPF ;Restore interupt flag
- POP CX
- POP BX
- POP AX
- RET
- ERROR_BEEP ENDP
-
- ;This procedure checks the ROM keyboard buffer to see if some program
- ;tried to clear this buffer. We know it's been cleared when the ROM
- ;tail and header overlap. Normally, the new procedures below keep the
- ;dummy character, word 0,in the buffer.
- ;
- ;Uses: BX,DS
- ;Writes: BUFFER_HEAD,BUFFER_TAIL,ROM_BUFFER_HEAD,
- ; ROM_BUFFER_TAIL
- ;Reads: KEYBOARD_BUFFER,KB_BUFFER
-
- CHECK_CLEAR_BUFFER PROC NEAR
- ASSUME DS:ROM_BIOS_DATA
- MOV BX,ROM_BIOS_DATA ;Establish pointer to BIOS data
- MOV DS,BX
- CLI ;Turn off interupts during this check
- MOV BX,ROM_BUFFER_HEAD ;check to see if buffer cleared
- CMP BX,ROM_BUFFER_TAIL ;Is the buffer empty?
- JNE BUFFER_OK ;No, then everything is alright
- ;Yes, then clear the internal buffer
- MOV BX,OFFSET KB_BUFFER ;Reset buffer with word 0 in buffer
- MOV ROM_BUFFER_HEAD,BX
- ADD BX,2
- MOV ROM_BUFFER_TAIL,BX
- ASSUME DS:CODE_SEG
- MOV BX,CS
- MOV DS,BX
- MOV BX,OFFSET KEYBOARD_BUFFER ;Reset internal buffer
- MOV BUFFER_HEAD,BX
- MOV BUFFER_TAIL,BX
- BUFFER_OK:
- ASSUME DS:CODE_SEG
- STI ;Interupts back on
- RET
- CHECK_CLEAR_BUFFER ENDP
-
- ;This procedure intercepts the keyboard interrupt and moves any new
- ;characters to the internal, 80 character buffer.
-
- INTERCEPT_KEYBOARD_INT PROC NEAR
- ASSUME DS:NOTHING
- PUSH DS
- PUSH SI
- PUSH BX
- PUSH AX
- CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
- PUSHF
- CALL ROM_KEYBOARD_INT ;Read scan code with BIOS routines
- ;----- Transfer any characters to internal buffer
- ASSUME DS:ROM_BIOS_DATA
- MOV BX,ROM_BIOS_DATA ;Establish pointer to BIOS data
- MOV DS,BX
- MOV SI,BUFFER_TAIL
- MOV BX,ROM_BUFFER_HEAD ;Check if real characters in buffer
- INC BX ;Skip over dummy character
- INC BX
- CMP BX,OFFSET KB_BUFFER_END
- JB DONT_WRAP ;No need to wrap the pointer
- MOV BX,OFFSET KB_BUFFER ;Wrap the pointer
- DONT_WRAP:
- CMP BX,ROM_BUFFER_TAIL ;Is there a real character?
- JE NO_NEW_CHARACTERS ;No then return to caller
- MOV AX,[BX] ;Yes,move character to internal buffer
- MOV CS:[SI],AX
- INC SI
- INC SI ;Move to next position
- CMP SI,OFFSET KEYBOARD_BUFFER_END
- JB NOT_AT_END
- MOV SI,OFFSET KEYBOARD_BUFFER
- NOT_AT_END:
- CMP SI,BUFFER_HEAD ;Buffer overrun?
- JNE WRITE_TO_BUFFER ;Yes beep and throw out character
- CALL ERROR_BEEP
- JMP SHORT NOT_AT_KB_END
- WRITE_TO_BUFFER:
- MOV BUFFER_TAIL,SI
- NOT_AT_KB_END:
- MOV ROM_BUFFER_HEAD,BX
-
- NO_NEW_CHARACTERS:
- ;---- See if CTRL + ALT pushed, and clear buffer if so
-
- MOV AL,KBD_FLAG ;Get status of shift keys into AL
- AND AL,0CH ;Isolate Alt and Crtl shift flags
- CMP AL,0CH ;Are both the Alt and Crtl keys down?
- JNE DONT_CLEAR_BUFFER ;No, then dont clear the buffer
- MOV AX,BUFFER_TAIL ;Yes, then clear the buffer
- MOV BUFFER_HEAD,AX
-
- DONT_CLEAR_BUFFER:
- POP AX
- POP BX
- POP SI
- POP DS
- IRET
- INTERCEPT_KEYBOARD_INT ENDP
-
- ;-----------------------------------------------------------------------;
- ;This procedure replaces the ROM BIOS routines for reading a character ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:CODE_SEG
- INTERCEPT_KEYBOARD_IO PROC FAR
- STI ;Interrupts back on
- PUSH DS ;Save current DS
- PUSH BX ;Save BX temporarily
- CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
- MOV BX,CS ;Establish pointer to data area
- MOV DS,BX
- OR AH,AH ;AH=0?
- JZ READ_CHARACTER ;Yes, read a character
- DEC AH ;AH=1?
- JZ READ_STATUS ;Yes, return the status
- DEC AH ;AH=2?
- JZ READ_SHIFT_STATUS ;Yes, return shift status
- POP BX ;Ignore the other function numbers
- POP DS
- IRET
-
- ;---- Read the key
-
- READ_CHARACTER: ;ASCII read
- STI ;Interrupts back on during loop
- NOP ;Allow an interrupt to occur
- CLI ;Interrupts back off
- MOV BX,BUFFER_HEAD ;Get pointer to head of buffer
- CMP BX,BUFFER_TAIL ;Test end of buffer
- JE READ_CHARACTER ;Loop until something in buffer
- MOV AX,[BX] ;Get scan code and ASCII code
- ADD BX,2 ;Move to next word in buffer
- CMP BX,OFFSET KEYBOARD_BUFFER_END ;At end of buffer?
- JNE SAVE_POINTER ;No, continue
- MOV BX,OFFSET KEYBOARD_BUFFER ;Yes, reset to buffer start
- SAVE_POINTER:
- MOV BUFFER_HEAD,BX ;Store value in variable
- POP BX
- POP DS
- IRET ;Return to caller
-
- ;---- ASCII status
-
- READ_STATUS:
- CLI ;Interrupts off
- MOV BX,BUFFER_HEAD ;Get head pointer
- CMP BX,BUFFER_TAIL ;If equal (ZF=1) then nothing there
- MOV AX,[BX]
- STI ;Interrupts back on
- POP BX ;Recover registers
- POP DS
- RET 2 ;Throw away flags
-
- READ_SHIFT_STATUS:
- JMP ROM_KEYBOARD_IO ;Let ROM routines do this
- INTERCEPT_KEYBOARD_IO ENDP
-
- ;-----------------------------------------------------------------;
- ;This procedure initializes the interrupt vectors. ;
- ;-----------------------------------------------------------------;
- INIT_VECTORS PROC NEAR
- ASSUME DS:VECTORS
- PUSH DS ;Save old Data Segment
- MOV AX,VECTORS ;Set up the data segment for vectors
- MOV DS,AX
- CLI ;Dont allow interrupts
-
- MOV AX,KEYBOARD_INT_VECTOR ;Save addresses of BIOS routines
- MOV ROM_KEYBOARD_INT,AX
- MOV AX,KEYBOARD_INT_VECTOR[2]
- MOV ROM_KEYBOARD_INT[2],AX
- ;Set up new KEYBOARD_INT vector
- MOV KEYBOARD_INT_VECTOR,OFFSET INTERCEPT_KEYBOARD_INT
- MOV KEYBOARD_INT_VECTOR[2],CS
- STI ;Allow interrupts again
- ;Set up KEYBOARD_IO vector
- MOV AX,KEYBOARD_IO_VECTOR
- MOV ROM_KEYBOARD_IO,AX
- MOV AX,KEYBOARD_IO_VECTOR[2]
- MOV ROM_KEYBOARD_IO[2],AX
- MOV KEYBOARD_IO_VECTOR,OFFSET INTERCEPT_KEYBOARD_IO
- MOV KEYBOARD_IO_VECTOR[2],CS
- ;Now set up the the kbd buffer, etc.
-
- ASSUME DS:ROM_BIOS_DATA
- MOV AX,ROM_BIOS_DATA
- MOV DS,AX
- CLI ;Dont allow interrupts now
- MOV BX,OFFSET KB_BUFFER
- MOV ROM_BUFFER_HEAD,BX
- MOV WORD PTR [BX],0
- ADD BX,2
- MOV ROM_BUFFER_TAIL,BX
- STI ;Allow interrupts again
-
- MOV DX,OFFSET INIT_VECTORS ;End of resident portions
- INT 27H ;Terminate but stay resident
- INIT_VECTORS ENDP
-
- CODE_SEG ENDS
-
- END BEGIN